// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using Interprise.Licensing.Base.Services;
using System.Data;
using System.Web;
using System.Data.SqlClient;

namespace InterpriseSuiteEcommerceCommon.InterpriseIntegration.Authentication
{
    public class ISSIUserAccount
    {
        #region Variable Declaration

        private string _userCode            = string.Empty;
        private bool _isAuthenticated       = false;
        private int _badLoginCount          = 0;
        private DateTime _lastBadLoginDate  = DateTime.MinValue;
        private DateTime _lockedUntilDate   = DateTime.MinValue;
        private string _passwordCypher      = string.Empty;
        private string _saltBase64          = string.Empty;
        private string _ivBase64            = string.Empty;
        private string _languageCode        = string.Empty;
        private string _localeSetting       = string.Empty;
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        private ISSIUserAccount(string userCode, string passwordCypher, string salt, string iv, int badLoginCount, DateTime lastBadLogin, DateTime lockedUntil)
        {
            _userCode = userCode;
            _passwordCypher = passwordCypher;
            _saltBase64 = salt;
            _ivBase64 = iv;
            _badLoginCount = badLoginCount;
            _lastBadLoginDate = lastBadLogin;
            _lockedUntilDate = lockedUntil;
        }
        #endregion

        #region Properties

        #region IsAuthenticated
        /// <summary>
        /// Gets whether the account is authenticated
        /// </summary>
        public bool IsAuthenticated
        {
            get { return _isAuthenticated; }
        }
        #endregion

        #region UserCode
        /// <summary>
        /// Gets the Uesr Code
        /// </summary>
        public string UserCode
        {
            get { return _userCode; }
        }
        #endregion

        #region BadLoginCount
        /// <summary>
        /// Gets the bad login count of this user
        /// </summary>
        public int BadLoginCount
        {
            get { return _badLoginCount; }
        }
        #endregion

        #region IsAboutToReachTheBadLoginLimit
        /// <summary>
        /// Gets whether the appconfig MaxBadLogins is about to be reached
        /// </summary>
        /// <returns></returns>
        public bool IsAboutToReachTheBadLoginLimit
        {
            get{ return (_badLoginCount + 1) >= AppLogic.AppConfigNativeInt("MaxBadLogins");}
        }
        #endregion

        #region LastBadLogin
        /// <summary>
        /// Gets the date the user logged in invalid
        /// </summary>
        public DateTime LastBadLogin
        {
            get { return _lastBadLoginDate; }
        }
        #endregion

        #region IsLocked        
        /// <summary>
        /// Gets whether the account is locked
        /// </summary>
        public bool IsLocked
        {
            get { return _lockedUntilDate >= DateTime.Now; }
        }
        #endregion

        #region LockedUntil
        /// <summary>
        /// Gets Locked Until Date
        /// </summary>
        public DateTime LockedUntil
        {
            get { return _lockedUntilDate; }
        }
        #endregion

        #region LanguageCode
        /// <summary>
        /// Gets the LanguageCode for this User Account
        /// </summary>
        public string LanguageCode
        {
            get { return _languageCode; }
            set { _languageCode = value; }
        }

        #endregion

        #region LocaleSetting        
        /// <summary>
        /// Gets the Locale setting for this User Account
        /// </summary>
        public string LocaleSetting
        {
            get { return _localeSetting; }
            set { _localeSetting = value; }
        }

        #endregion

        #region Authenticate
        /// <summary>
        /// Authenticates the user password
        /// </summary>
        /// <param name="password"></param>
        /// <returns></returns>
        public bool Authenticate(string password)
        {
            byte[] salt = Convert.FromBase64String(_saltBase64);
            byte[] iv = Convert.FromBase64String(_ivBase64);

            // compare cypher...
            CryptoServiceProvider crypto = new CryptoServiceProvider();
            string encrypted = crypto.Encrypt(password, salt, iv);
            _isAuthenticated = _passwordCypher.Equals(encrypted);

            if (_isAuthenticated)
            {
                ClearSecurityRestrictions();
            }

            return _isAuthenticated;
        }
        #endregion

        #endregion

        #region Methods

        #region Find
        /// <summary>
        /// Find the user account based on the user code
        /// </summary>
        /// <param name="userCode"></param>
        /// <returns></returns>
        public static ISSIUserAccount Find(string userCode)
        {
            ISSIUserAccount account = null;
            String sqlQuery = String.Empty;
            string[] args = null ;
            Boolean isAllowWebAccess = userCode.Equals("webadmin", StringComparison.InvariantCultureIgnoreCase);
            if (isAllowWebAccess)
            {
                sqlQuery ="exec eCommerceGetUserAccount @UserCode = {0}";
                args = new string[] { DB.SQuote(userCode) };
            }
            else
            { 
                sqlQuery = "exec ReadeCommerceUserAccounts @UserCode = {0} , @WebSiteCode = {1}";
                args = new string[] { DB.SQuote(userCode), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) };
            }

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, sqlQuery, args))
                {
                    if (reader.Read())
                    {
                        if (!isAllowWebAccess)
                        {
                            isAllowWebAccess = DB.RSFieldBool(reader, "IsWebAccess") == true;
                        }

                        if (isAllowWebAccess)
                        {
                            account =
                            new ISSIUserAccount(DB.RSField(reader, "UserCode"),
                                DB.RSField(reader, "UserPassword"),
                                DB.RSField(reader, "UserPasswordSalt"),
                                DB.RSField(reader, "UserPasswordIV"),
                                DB.RSFieldInt(reader, "BadLoginCount"),
                                DB.RSFieldDateTime(reader, "LastBadLogin"),
                                DB.RSFieldDateTime(reader, "LockedUntil")
                            );

                            account.LanguageCode = DB.RSField(reader, "LanguageCode");
                            account.LocaleSetting = Localization.CheckLocaleSettingForProperCase(DB.RSField(reader, "LocaleSetting"));
                        }
                    }
                }
            }
            
            return account;
        }
        #endregion

        #region IncrementBadLoginCount
        /// <summary>
        /// Increments the bad login count
        /// </summary>
        public void IncrementBadLoginCount()
        {
            if (!IsAboutToReachTheBadLoginLimit)
            {
                // update the bad login count
                DB.ExecuteSQL("UPDATE SystemUserAccount SET BadLoginCount = BadLoginCount+1, LastBadLogin = {0} WHERE UserCode = {1}", DB.SQuote(Localization.DateTimeStringForDB(DateTime.Now)), DB.SQuote(_userCode));

                Refresh();                
            }
            else
            {
                throw new InvalidOperationException("Maximum Bad Login about to be reached... Lock the account instead!!!");
            }
        }
        #endregion

        #region LockAccount        
        /// <summary>
        /// Locks this particular user account based on the setting in the appconfig BadLoginLockTimeOut
        /// </summary>
        public void LockAccount()
        {
            // first clear the bad login count
            DB.ExecuteSQL("UPDATE SystemUserAccount SET BadLoginCount = 0 WHERE Usercode = {0}", DB.SQuote(_userCode));

            // now lock the account
            DateTime lockTimeOut = DateTime.Now.AddMinutes(AppLogic.AppConfigUSInt("BadLoginLockTimeOut"));
            DB.ExecuteSQL("UPDATE SystemUserAccount SET LockedUntil = {0} WHERE UserCode = {1}", DB.SQuote(Localization.DateTimeStringForDB(lockTimeOut)), DB.SQuote(_userCode));

            Refresh();
        }
        #endregion

        #region Refresh
        /// <summary>
        /// Refreshes the info
        /// </summary>
        private void Refresh()
        {
            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT BadLoginCount, LastBadLogin, LockedUntil FROM SystemUserAccount with (NOLOCK) WHERE UserCode = {0}", DB.SQuote(_userCode)))
                {
                    // must be able to read successfully!!!
                    reader.Read();

                    _badLoginCount = DB.RSFieldInt(reader, "BadLoginCount");
                    _lastBadLoginDate = DB.RSFieldDateTime(reader, "LastBadLogin");
                    _lockedUntilDate = DB.RSFieldDateTime(reader, "LockedUntil");
                }
            }
        }
        #endregion

        #region ClearSecurityRestrictions
        /// <summary>
        /// Clears the applicable security restrictions as per PABP
        /// </summary>
        private void ClearSecurityRestrictions()
        {
            DB.ExecuteSQL("UPDATE SystemUserAccount SET BadLoginCount = 0, LastBadLogin = NULL, LockedUntil = NULL WHERE UserCode = {0}", DB.SQuote(_userCode));
        }
        #endregion

        #region Current
        
        /// <summary>
        /// Gets the currently authenticated user
        /// </summary>
        public static ISSIUserAccount Current
        {
            get 
            {
                if (HttpContext.Current.User is ISSIUserPrincipal)
                {
                    return (HttpContext.Current.User as ISSIUserPrincipal).UserAccount;
                }

                return null;
            }
        }

        #endregion

        #endregion
    }
}



